package be.kul.osgi.ds.messageservice;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Properties;

public class MessageObject
{
		// Explicitly set for compatibility between standard and micro version
		private static final long serialVersionUID=3945353187608998130L;
		
		/** constant identifying the FIPA performative **/
		public static final int ACCEPT_PROPOSAL = 0;
		/** constant identifying the FIPA performative **/
		public static final int AGREE = 1;
		/** constant identifying the FIPA performative **/
		public static final int CANCEL = 2;
		/** constant identifying the FIPA performative **/
		public static final int CFP = 3;
		/** constant identifying the FIPA performative **/
		public static final int CONFIRM = 4;
		/** constant identifying the FIPA performative **/
		public static final int DISCONFIRM = 5;
		/** constant identifying the FIPA performative **/
		public static final int FAILURE = 6;
		/** constant identifying the FIPA performative **/
		public static final int INFORM = 7;
		/** constant identifying the FIPA performative **/
		public static final int INFORM_IF = 8;
		/** constant identifying the FIPA performative **/
		public static final int INFORM_REF = 9;
		/** constant identifying the FIPA performative **/
		public static final int NOT_UNDERSTOOD = 10;
		/** constant identifying the FIPA performative **/
		public static final int PROPOSE = 11;
		/** constant identifying the FIPA performative **/
		public static final int QUERY_IF = 12;
		/** constant identifying the FIPA performative **/
		public static final int QUERY_REF = 13;
		/** constant identifying the FIPA performative **/
		public static final int REFUSE = 14;
		/** constant identifying the FIPA performative **/
		public static final int REJECT_PROPOSAL = 15;
		/** constant identifying the FIPA performative **/
		public static final int REQUEST = 16;
		/** constant identifying the FIPA performative **/
		public static final int REQUEST_WHEN = 17;
		/** constant identifying the FIPA performative **/
		public static final int REQUEST_WHENEVER = 18;
		/** constant identifying the FIPA performative **/
		public static final int SUBSCRIBE = 19;
		/** constant identifying the FIPA performative **/
		public static final int PROXY = 20;
		/** constant identifying the FIPA performative **/
		public static final int PROPAGATE = 21;
		/** constant identifying the GETID performative **/
		public static final int GETID = 22;
		/** constant identifying the SENDID performative **/
		public static final int SENDID = 23;
		/** constant identifying the GETID performative **/
		public static final int ASKBUNDLE = 24;
		/** constant identifying the SENDID performative **/
		public static final int GIVEBUNDLE = 25;
		/** constant identifying the GETID performative **/
		public static final int ASKROLE = 26;
		/** constant identifying the SENDID performative **/
		public static final int GIVEROLE = 27;
		/** constant identifying an unknown performative **/
		public static final int UNKNOWN = -1;
		
		/**
		 @serial
		 */
		private int performative; // keeps the performative type of this object
		/** This array of Strings keeps the names of the performatives **/
		private static final String[] performatives = new String[28];
		static { // initialization of the Vector of performatives
			performatives[ACCEPT_PROPOSAL]="ACCEPT-PROPOSAL";
			performatives[AGREE]="AGREE";
			performatives[CANCEL]="CANCEL";
			performatives[CFP]="CFP";
			performatives[CONFIRM]="CONFIRM";
			performatives[DISCONFIRM]="DISCONFIRM";
			performatives[FAILURE]="FAILURE";
			performatives[INFORM]="INFORM";
			performatives[INFORM_IF]="INFORM-IF";
			performatives[INFORM_REF]="INFORM-REF";
			performatives[NOT_UNDERSTOOD]="NOT-UNDERSTOOD";
			performatives[PROPOSE]="PROPOSE";
			performatives[QUERY_IF]="QUERY-IF";
			performatives[QUERY_REF]="QUERY-REF";
			performatives[REFUSE]="REFUSE";
			performatives[REJECT_PROPOSAL]="REJECT-PROPOSAL";
			performatives[REQUEST]="REQUEST";
			performatives[REQUEST_WHEN]="REQUEST-WHEN";
			performatives[REQUEST_WHENEVER]="REQUEST-WHENEVER";
			performatives[SUBSCRIBE]="SUBSCRIBE";
			performatives[PROXY]="PROXY";
			performatives[PROPAGATE]="PROPAGATE";
			performatives[GETID]="GETID";
			performatives[SENDID]="SENDID";
			performatives[ASKBUNDLE]="ASKBUNDLE";
			performatives[GIVEBUNDLE]="GIVEBUNDLE";
			performatives[ASKROLE]="ASKROLE";
			performatives[GIVEROLE]="GIVEROLE";
		}
		
		/**
		 * User defined parameter key specifying, when set to "true", that if the delivery of a 
		 * message fails, no FAILURE notification has to be sent back to the sender.
		 */
		public static final String IGNORE_FAILURE = "JADE-ignore-failure";
		
		/**
		 * User defined parameter key specifying that the corresponding value must be replaced by the JADE runtime
		 * by an ISO8601 encoded time-stamp at posting time.
		 */
		public static final String POST_TIME_STAMP = "JADE-post-ts";
		
		/**
		 * User defined parameter key specifying that the JADE tracing mechanism should be activated for this message.
		 */
		public static final String TRACE = "JADE-trace";

		/**
		 * User defined parameter key specifying that this message does not need to be cloned by the message delivery service.
		 * This should be used ONLY when the message object will not be modified after being sent
		 */
		public static final String NO_CLONE = "JADE-no-clone";

		/**
		 * User defined parameter key specifying that this message must be delivered synchronously. It should 
		 * be noticed that when using synchronous delivery message order is not guaranteed.
		 */
		public static final String SYNCH_DELIVERY = "JADE-synch-delivery";

		/**
		 * User defined parameter key specifying the AID of the real sender of a message. This is automatically 
		 * set by the MessagingService when posting a message where the sender field is different than the real 
		 * sender.
		 */
		public static final String REAL_SENDER = "JADE-real-sender";

		/**
		 * AMS failure reasons 
		 */
		public static final String AMS_FAILURE_AGENT_NOT_FOUND = "Agent not found";
		public static final String AMS_FAILURE_AGENT_UNREACHABLE = "Agent unreachable";
		public static final String AMS_FAILURE_SERVICE_ERROR = "Service error";
		public static final String AMS_FAILURE_UNAUTHORIZED = "Not authorized";
		public static final String AMS_FAILURE_FOREIGN_AGENT_UNREACHABLE = "Foreign agent unreachable";
		public static final String AMS_FAILURE_FOREIGN_AGENT_NO_ADDRESS = "Foreign agent with no address";
		public static final String AMS_FAILURE_UNEXPECTED_ERROR = "Unexpected error";


		/**
		 @serial
		 */
		private String source = null;
		
		/** These constants represent the expected size of the 2 array lists
		 * used by this class **/
		private static final int RECEIVERS_EXPECTED_SIZE = 1;
		private static final int REPLYTO_EXPECTED_SIZE = 1;

		//#MIDP_EXCLUDE_BEGIN
		private ArrayList dests = new ArrayList(RECEIVERS_EXPECTED_SIZE);
		private ArrayList reply_to = null; 
		//#MIDP_EXCLUDE_END
		/*#MIDP_INCLUDE_BEGIN
		 private Vector dests = new Vector(RECEIVERS_EXPECTED_SIZE);
		 private Vector reply_to = null; 
		 #MIDP_INCLUDE_END*/
		
		private String Receiver;
		
		/**
		 @serial
		 */
		// At a given time or content or byteSequenceContent are != null,
		// it is not allowed that both are != null
		private String content = null;
		
		/**
		 @serial
		 */
		private String reply_with = null;
		
		/**
		 @serial
		 */
		private String in_reply_to = null;
		
		/**
		 @serial
		 */
		private String encoding = null;
		
		/**
		 @serial
		 */
		private String language = null;
		
		/**
		 @serial
		 */
		private String ontology = null;
		
		/**
		 @serial
		 */
		private long reply_byInMillisec = 0; 
		
		/**
		 @serial
		 */
		private String protocol = null;
		
		/**
		 @serial
		 */
		private String conversation_id = null;
		
		private Properties userDefProps = null; 
		//#CUSTOM_EXCLUDE_BEGIN
		
		/**
		 Returns the list of the communicative acts as an array of <code>String</code>.
		 */
		public static String[] getAllPerformativeNames()
		{
			return performatives;
		}
		
		/**
		 @deprecated Since every ACL Message must have a message type, you
		 should use the new constructor which gets a message type as a
		 parameter.  To avoid problems, now this constructor silently sets
		 the message type to <code>not-understood</code>.
		 @see jade.lang.acl.ACLMessage#ACLMessage(int)
		 */
		public MessageObject() { // Used by persistence service: do not remove it, but make it private
			performative = NOT_UNDERSTOOD;
		}
		
		
		
		
		/**
		 * This constructor creates an ACL message object with the specified
		 * performative. If the passed integer does not correspond to any of
		 * the known performatives, it silently initializes the message to
		 * <code>not-understood</code>.
		 **/
		public MessageObject(int perf) {
			performative = perf;
		}
		
		/**
		 Writes the <code>:sender</code> slot. <em><b>Warning:</b> no
		 checks are made to validate the slot value.</em>
		 @param source The new value for the slot.
		 @see jade.lang.acl.ACLMessage#getSender()
		 */
		public void setSender(String s) {
			source = s; 
		}
		
		/**
		 Adds a value to <code>:receiver</code> slot. <em><b>Warning:</b>
		 no checks are made to validate the slot value.</em>
		 @param r The value to add to the slot value set.
		 */
		public void addReceiver(String r) {
			if(r != null) {
				//#MIDP_EXCLUDE_BEGIN
				dests.add(r);
				//#MIDP_EXCLUDE_END
				/*#MIDP_INCLUDE_BEGIN
				 dests.addElement(r);
				 #MIDP_INCLUDE_END*/
			}
		}
		
		/**
		 Removes a value from <code>:receiver</code>
		 slot. <em><b>Warning:</b> no checks are made to validate the slot
		 value.</em>
		 @param r The value to remove from the slot value set.
		 @return true if the AID has been found and removed, false otherwise
		 */
		public boolean removeReceiver(String r) {
			if (r != null) {
				//#MIDP_EXCLUDE_BEGIN
				return dests.remove(r);
				//#MIDP_EXCLUDE_END
				/*#MIDP_INCLUDE_BEGIN
				 return dests.removeElement(r);
				 #MIDP_INCLUDE_END*/
			}
			else {
				return false;
			}
		}
		
		/**
		 Removes all values from <code>:receiver</code>
		 slot. <em><b>Warning:</b> no checks are made to validate the slot
		 value.</em> 
		 */
		public void clearAllReceiver() {
			//#MIDP_EXCLUDE_BEGIN
			dests.clear();
			//#MIDP_EXCLUDE_END
			/*#MIDP_INCLUDE_BEGIN
			 dests.removeAllElements();
			 #MIDP_INCLUDE_END*/
		}
		
		
		
		/**
		 Adds a value to <code>:reply-to</code> slot. <em><b>Warning:</b>
		 no checks are made to validate the slot value.</em>
		 @param dest The value to add to the slot value set.
		 */
		public void addReplyTo(String dest) {
			if (dest != null) { 
				//#MIDP_EXCLUDE_BEGIN
				reply_to = (reply_to == null ? new ArrayList(REPLYTO_EXPECTED_SIZE) : reply_to);
				reply_to.add(dest);
				//#MIDP_EXCLUDE_END
				/*#MIDP_INCLUDE_BEGIN
				 reply_to = (reply_to == null ? new Vector(REPLYTO_EXPECTED_SIZE) : reply_to);
				 reply_to.addElement(dest);
				 #MIDP_INCLUDE_END*/
			}
		}
		
		/**
		 Removes a value from <code>:reply_to</code>
		 slot. <em><b>Warning:</b> no checks are made to validate the slot
		 value.</em>
		 @param dest The value to remove from the slot value set.
		 @return true if the AID has been found and removed, false otherwise
		 */
		public boolean removeReplyTo(String dest) {
			if ((dest != null) && (reply_to != null) ) {
				//#MIDP_EXCLUDE_BEGIN
				return reply_to.remove(dest);
				//#MIDP_EXCLUDE_END
				/*#MIDP_INCLUDE_BEGIN
				 return reply_to.removeElement(dest);
				 #MIDP_INCLUDE_END*/ 
			}
			else {
				return false;
			}
		}
		
		/**
		 Removes all values from <code>:reply_to</code>
		 slot. <em><b>Warning:</b> no checks are made to validate the slot
		 value.</em> 
		 */
		public void clearAllReplyTo() {
			if (reply_to != null) {
				//#MIDP_EXCLUDE_BEGIN
				reply_to.clear();
				//#MIDP_EXCLUDE_END
				/*#MIDP_INCLUDE_BEGIN
				 reply_to.removeAllElements();
				 #MIDP_INCLUDE_END*/
			}
		}
		
		/**
		 * set the performative of this ACL message object to the passed constant.
		 * Remind to 
		 * use the set of constants (i.e. <code> INFORM, REQUEST, ... </code>)
		 * defined in this class
		 */
		public void setPerformative(int perf) {
			performative = perf;
		}
		
		/**
		 * Writes the <code>:content</code> slot. <em><b>Warning:</b> no
		 * checks are made to validate the slot value.</em> <p>
		 * <p>Notice that, in general, setting a String content and getting
		 * back a byte sequence content - or viceversa - does not return
		 * the same value, i.e. the following relation does not hold
		 * <code>
		 * getByteSequenceContent(setByteSequenceContent(getContent().getBytes())) 
		 * is equal to getByteSequenceContent()
		 * </code>
		 * @param content The new value for the slot.
		 * @see jade.lang.acl.ACLMessage#getContent()
		 * @see jade.lang.acl.ACLMessage#setByteSequenceContent(byte[])
		 * @see jade.lang.acl.ACLMessage#setContentObject(Serializable s)
		 */
		public void setContent(String content) {
			this.content = null; 
			if (content != null) {
				this.content = content;
			}
			else {
				this.content = null;
			}
			//System.out.println("@MessageObject : Content was set : "+ this.content);
		}
		
			
		
		/**
		 Writes the <code>:reply-with</code> slot. <em><b>Warning:</b> no
		 checks are made to validate the slot value.</em>
		 @param reply The new value for the slot.
		 @see jade.lang.acl.ACLMessage#getReplyWith()
		 */
		public void setReplyWith(String reply) {
			reply_with = reply; 
		}
		
		/**
		 Writes the <code>:in-reply-to</code> slot. <em><b>Warning:</b> no
		 checks are made to validate the slot value.</em>
		 @param reply The new value for the slot.
		 @see jade.lang.acl.ACLMessage#getInReplyTo()
		 */
		public void setInReplyTo(String reply) {
			in_reply_to = reply;
		}
		
		/**
		 Writes the <code>:encoding</code> slot. <em><b>Warning:</b> no
		 checks are made to validate the slot value.</em>
		 @param str The new value for the slot.
		 @see jade.lang.acl.ACLMessage#getEncoding()
		 */
		public void setEncoding(String str) {
			encoding = str;
		}
		
		/**
		 Writes the <code>:language</code> slot. <em><b>Warning:</b> no
		 checks are made to validate the slot value.</em>
		 @param str The new value for the slot.
		 @see jade.lang.acl.ACLMessage#getLanguage()
		 */
		public void setLanguage(String str) {
			language = str;
		}
		
		/**
		 Writes the <code>:ontology</code> slot. <em><b>Warning:</b> no
		 checks are made to validate the slot value.</em>
		 @param str The new value for the slot.
		 @see jade.lang.acl.ACLMessage#getOntology()
		 */
		public void setOntology(String str) {
			ontology = str;
		}
		
		
		/**
		 Writes the <code>:reply-by</code> slot. <em><b>Warning:</b> no
		 checks are made to validate the slot value.</em>
		 @param date The new value for the slot.
		 @see jade.lang.acl.ACLMessage#getReplyByDate()
		 */
		public void setReplyByDate(Date date) {
			reply_byInMillisec = (date==null?0:date.getTime());
		}
		
		/**
		 Writes the <code>:protocol</code> slot. <em><b>Warning:</b> no
		 checks are made to validate the slot value.</em>
		 @param str The new value for the slot.
		 @see jade.lang.acl.ACLMessage#getProtocol()
		 */
		public void setProtocol( String str ) {
			protocol = str;
		}
		
		/**
		 Writes the <code>:conversation-id</code> slot. <em><b>Warning:</b> no
		 checks are made to validate the slot value.</em>
		 @param str The new value for the slot.
		 @see jade.lang.acl.ACLMessage#getConversationId()
		 */
		public void setConversationId( String str ) {
			conversation_id = str;
		}
		
		
		
		/**
		 Reads <code>:receiver</code> slot.
		 @return An <code>Iterator</code> containing the Agent IDs of the
		 receiver agents for this message.
		 */
		public Iterator getAllReceiver() {
			//#MIDP_EXCLUDE_BEGIN
			return dests.iterator();
			//#MIDP_EXCLUDE_END
			/*#MIDP_INCLUDE_BEGIN
			 return new EnumIterator(dests.elements());
			 #MIDP_INCLUDE_END*/
		}
		
		/**
		 Reads <code>:reply_to</code> slot.
		 @return An <code>Iterator</code> containing the Agent IDs of the
		 reply_to agents for this message.
		 */
		public Iterator getAllReplyTo() {
			if (reply_to == null) {
				//return EmptyIterator.getInstance();
				return null;
			}
			else {
				//#MIDP_EXCLUDE_BEGIN
				return reply_to.iterator();
				//#MIDP_EXCLUDE_END
				/*#MIDP_INCLUDE_BEGIN
				 return new EnumIterator(reply_to.elements());
				 #MIDP_INCLUDE_END*/
			}
		}
		
		/**
		 Reads <code>:sender</code> slot.
		 @return The value of <code>:sender</code>slot.
		 @see jade.lang.acl.ACLMessage#setSender(AID).
		 */
		public String getSender() {
			return source;
		}
		
		/**
		 Returns the string corresponding to the integer for the performative
		 @return the string corresponding to the integer for the performative; 
		 "NOT-UNDERSTOOD" if the integer is out of range.
		 */
		public static String getPerformative(int perf){
			try {
				return performatives[perf];
			} catch (Exception e) {
				return performatives[NOT_UNDERSTOOD];
			}
		}
		
		/**
		 Returns the integer corresponding to the performative
		 @returns the integer corresponding to the performative; -1 otherwise
		 */
		public static int getInteger(String perf)
		{
			String tmp = perf.toUpperCase();
			for (int i=0; i<performatives.length; i++)
				if (performatives[i].equals(tmp))
					return i;
			return -1;
		}
		
		
		
		/**
		 * return the integer representing the performative of this object
		 * @return an integer representing the performative of this object
		 */
		public int getPerformative() {
			return performative;
		}
		
		/**
		 * Reads <code>:content</code> slot. <p>
		 * <p>Notice that, in general, setting a String content and getting
		 * back a byte sequence content - or viceversa - does not return
		 * the same value, i.e. the following relation does not hold
		 * <code>
		 * getByteSequenceContent(setByteSequenceContent(getContent().getBytes())) 
		 * is equal to getByteSequenceContent()
		 * </code>
		 * @return The value of <code>:content</code> slot.
		 * @see jade.lang.acl.ACLMessage#setContent(String)
		 * @see jade.lang.acl.ACLMessage#getByteSequenceContent()
		 * @see jade.lang.acl.ACLMessage#getContentObject()
		 */
		public String getContent() {
			if(content != null)
				return new String(content);
			else if (content != null)
				return new String(content);
			return null;
		}
		
		/**
		 Reads <code>:reply-with</code> slot.
		 @return The value of <code>:reply-with</code>slot.
		 @see jade.lang.acl.ACLMessage#setReplyWith(String).
		 */
		public String getReplyWith() {
			return reply_with;
		}
		
		/**
		 Reads <code>:reply-to</code> slot.
		 @return The value of <code>:reply-to</code>slot.
		 @see jade.lang.acl.ACLMessage#setInReplyTo(String).
		 */
		public String getInReplyTo() {
			return in_reply_to;
		}
		
		
		
		/**
		 Reads <code>:encoding</code> slot.
		 @return The value of <code>:encoding</code>slot.
		 @see jade.lang.acl.ACLMessage#setEncoding(String).
		 */
		public String getEncoding() {
			return encoding;
		}
		
		/**
		 Reads <code>:language</code> slot.
		 @return The value of <code>:language</code>slot.
		 @see jade.lang.acl.ACLMessage#setLanguage(String).
		 */
		public String getLanguage() {
			return language;
		}
		
		/**
		 Reads <code>:ontology</code> slot.
		 @return The value of <code>:ontology</code>slot.
		 @see jade.lang.acl.ACLMessage#setOntology(String).
		 */
		public String getOntology() {
			return ontology;
		}
		
		
		/**
		 Reads <code>:reply-by</code> slot.
		 @return The value of <code>:reply-by</code>slot, as a
		 <code>Date</code> object.
		 @see jade.lang.acl.ACLMessage#setReplyByDate(Date).
		 */
		public Date getReplyByDate() {
			if(reply_byInMillisec != 0)
				return new Date(reply_byInMillisec);
			else
				return null;
		}
		
		/**
		 Reads <code>:protocol</code> slot.
		 @return The value of <code>:protocol</code>slot.
		 @see jade.lang.acl.ACLMessage#setProtocol(String).
		 */
		public String getProtocol() {
			return protocol;
		}
		
		/**
		 Reads <code>:conversation-id</code> slot.
		 @return The value of <code>:conversation-id</code>slot.
		 @see jade.lang.acl.ACLMessage#setConversationId(String).
		 */
		public String getConversationId() {
			return conversation_id;
		}
		
		
		/**
		 * Add a new user defined parameter to this ACLMessage.
		 * Notice that according to the FIPA specifications, the keyword of a
		 * user-defined parameter must not contain space inside.
		 * Note that the user does not need to (and shall not) add the prefix "X-" to the keyword.
		 * This is automatically added by the StringACLCodec. 
		 * @param key the property key.
		 * @param value the property value
		 */
		public void addUserDefinedParameter(String key, String value) {
			userDefProps = (userDefProps == null ? new Properties() : userDefProps);
			userDefProps.setProperty(key,value);
		}
		
		/**
		 * Searches for the user defined parameter with the specified key. 
		 * The method returns
		 * <code>null</code> if the parameter is not found.
		 *
		 * @param   key   the parameter key.
		 * @return  the value in this ACLMessage with the specified key value.
		 */
		public String getUserDefinedParameter(String key){
			if (userDefProps == null)
				return null;
			else
				return userDefProps.getProperty(key);
		}

		/**
		 * Return all user defined parameters of this ACLMessage in form of a Properties object
		 **/
		public Properties getAllUserDefinedParameters() {
			userDefProps = (userDefProps == null ? new Properties() : userDefProps);
			return userDefProps; 
		}
		
		/**
		 * Replace all user defined parameters of this ACLMessage with the specified Properties object.
		 **/
		public void setAllUserDefinedParameters(Properties userDefProps) {
			this.userDefProps = userDefProps; 
		}
		
		/**
		 * Removes the key and its corresponding value from the list of user
		 * defined parameters in this ACLMessage.
		 * @param key the key that needs to be removed
		 @return true if the property has been found and removed, false otherwise
		 */
		public boolean removeUserDefinedParameter(String key) {
			return (clearUserDefinedParameter(key) != null);
		}
		
		/**
		 * Removes the key and its corresponding value from the list of user
		 * defined parameters in this ACLMessage.
		 * @param key the key that needs to be removed
		 * @return the value to which the key had been mapped or null if the key was not present
		 */
		public Object clearUserDefinedParameter(String key) {
			if (userDefProps == null)
				return null;
			else
				return userDefProps.remove(key);
		}
		
		/**
		 * Resets all the message slots.
		 */
		public void reset() {   
			source = null;
			//#MIDP_EXCLUDE_BEGIN
			dests.clear();
			if (reply_to != null)
				reply_to.clear();
			//#MIDP_EXCLUDE_END
			/*#MIDP_INCLUDE_BEGIN
			 dests.removeAllElements();
			 if (reply_to != null)
			 reply_to.removeAllElements();
			 #MIDP_INCLUDE_END*/
			performative = NOT_UNDERSTOOD;
			content = null;
			reply_with = null;
			in_reply_to = null;
			encoding = null;
			language = null;
			ontology = null;
			reply_byInMillisec = 0;
			protocol = null;
			conversation_id = null;
			if (userDefProps != null) {
				userDefProps.clear();
			}
		}
		
		/**
		 * create a new ACLMessage that is a reply to this message.
		 * In particular, it sets the following parameters of the new message:
		 * receiver, language, ontology, protocol, conversation-id,
		 * in-reply-to, reply-with.
		 * The programmer needs to set the communicative-act and the content.
		 * Of course, if he wishes to do that, he can reset any of the fields.
		 * @return the ACLMessage to send as a reply
		 */
		public Message createReply() {
			Message m = new Message(getPerformative());
			Iterator it = getAllReplyTo(); 
			while (it.hasNext())
				m.addReceiver((String)it.next());
			if ((reply_to == null) || reply_to.isEmpty())
				m.addReceiver(getSender());
			m.setLanguage(getLanguage());
			m.setOntology(getOntology());
			m.setProtocol(getProtocol());
			m.setInReplyTo(getReplyWith());
			if (source != null)
				m.setReplyWith(source + java.lang.System.currentTimeMillis()); 
			else
				m.setReplyWith("X"+java.lang.System.currentTimeMillis()); 
			m.setConversationId(getConversationId());
			// Copy only well defined user-def-params
			String trace = getUserDefinedParameter(TRACE);
			if (trace != null) {
				m.addUserDefinedParameter(TRACE, trace);
			}
			//#CUSTOM_EXCLUDE_BEGIN
			//Set the Aclrepresentation of the reply message to the aclrepresentation of the sent message 
		/*	if (messageEnvelope != null) {
				m.setDefaultEnvelope(); 
				String aclCodec= messageEnvelope.getAclRepresentation();
				if (aclCodec != null)
					m.getEnvelope().setAclRepresentation(aclCodec);
			}
			else
				m.setEnvelope(null);
			//#CUSTOM_EXCLUDE_END*/
			return m;
		}
		
	/**
		 retrieve the whole list of intended receivers for this message.
		 @return An Iterator over all the intended receivers of this
		 message taking into account the Envelope ":intended-receiver"
		 first, the Envelope ":to" second and the message ":receiver" 
		 last.
		 */
/*		public Iterator getAllIntendedReceiver() {
			Iterator it = null;
			//#CUSTOM_EXCLUDE_BEGIN
			//Envelope env = getEnvelope();
			if (env != null) {
				it = env.getAllIntendedReceiver();
				if (!it.hasNext()) {
					// The ":intended-receiver" field is empty --> try with the ":to" field 
					it = env.getAllTo();
				}
			}
			//#CUSTOM_EXCLUDE_END
			if (it == null || !it.hasNext()) {
				// Both the ":intended-receiver" and the ":to" fields are empty --> 
				// Use the ACLMessage receivers
				it = getAllReceiver();
			}
			return it;
		}
*/		
		//#MIDP_EXCLUDE_BEGIN
		
		
		
		// For persistence service
		private Long persistentID;
		
		// For persistence service
		private Long getPersistentID() {
			return persistentID;
		}
		
		// For persistence service
		private void setPersistentID(Long l) {
			persistentID = l;
		}
		
		
		
		// For persistence service
		private void setReceivers(ArrayList al) {
			dests = al;
		}
		
		// For persistence service
		private ArrayList getReceivers() {
			return dests;
		}
		
		// For persistence service
		private void setReplyTo(ArrayList al) {
			reply_to = al;
		}
		
		// For persistence service
		private ArrayList getReplyTo() {
			return reply_to;
		}
		
		// For persistence service
		private void setUserDefinedProperties(Serializable p) {
			userDefProps = (Properties)p;
		}
		
		// For persistence service
		private Serializable getUserDefinedProperties() {
			return userDefProps;
		}

		public String getReceiver() {
			return Receiver;
		}

		public void setReceiver(String receiver) {
			Receiver = receiver;
		}
		
		
		//#MIDP_EXCLUDE_END
	
	
}